/*
 *  CEDictMaker.cpp
 *  LID Library
 *
 *  Created by Alexander Trutchenko on 11/01/12.
 *  Copyright 2012 League of Independent Developers. All rights reserved.
 *
 */

#include "cocos2dx_extentions/localization/CEDictMaker.h"

#include "cocos2dx_extentions/localization/CEString.h"
#include "lid_lib/src/strings_and_localization/LLStringUtils.h"

#include "lid_lib/src/types/LLTypes.h"


using namespace cocos2d;
using namespace std;
using namespace lidlib;

namespace cocosext {


CCDictionary<std::string, CCObject*>* CEDictMaker::dictionaryWithContentsOfFile(const char *pFileName)
{
    CCSAXParser parser;

    if (false == parser.init("UTF-8"))
    {
        return NULL;
    }
    parser.setDelegator(this);

    parser.parse(pFileName);
    return m_pRootDict;
}

void CEDictMaker::startElement(void *ctx, const char *name, const char **atts)
{
    CC_UNUSED_PARAM(ctx);
    CC_UNUSED_PARAM(atts);
    std::string sName((char*)name);
    if( sName == "dict" )
    {
        m_pCurDict = new CCDictionary<std::string, CCObject*>();
        if(! m_pRootDict)
        {
            // Because it will call m_pCurDict->release() later, so retain here.
            m_pRootDict = m_pCurDict;
            m_pRootDict->retain();
        }
        m_tState = CE_SAX_DICT;

        ceSAXState preState = CE_SAX_NONE;
        if (! m_tStateStack.empty())
        {
            preState = m_tStateStack.top();
        }

        if (CE_SAX_ARRAY == preState)
        {
            // add the dictionary into the array
            m_pArray->addObject(m_pCurDict);
        }
        else if (CE_SAX_DICT == preState)
        {
            // add the dictionary into the pre dictionary
            CCAssert(! m_tDictStack.empty(), "The state is wrong!");
            CCDictionary<std::string, CCObject*>* pPreDict = m_tDictStack.top();
            pPreDict->setObject(m_pCurDict, m_sCurKey);
        }

        m_pCurDict->release();

        // record the dict state
        m_tStateStack.push(m_tState);
        m_tDictStack.push(m_pCurDict);
    }
    else if(sName == "key")
    {
        m_tState = CE_SAX_KEY;
    }
    else if(sName == "integer")
    {
        m_tState = CE_SAX_INT;
    }
    else if(sName == "real")
    {
        m_tState = CE_SAX_REAL;
    }
    else if(sName == "string")
    {
        m_tState = CE_SAX_STRING;
    }
    else if (sName == "array")
    {
        m_tState = CE_SAX_ARRAY;
        m_pArray = new CCMutableArray<CCObject*>();

        ceSAXState preState = m_tStateStack.empty() ? CE_SAX_DICT : m_tStateStack.top();
        if (preState == CE_SAX_DICT)
        {
            m_pCurDict->setObject(m_pArray, m_sCurKey);
        }
        else if (preState == CE_SAX_ARRAY)
        {
            CCAssert(! m_tArrayStack.empty(), "The state is worng!");
            CCMutableArray<CCObject*>* pPreArray = m_tArrayStack.top();
            pPreArray->addObject(m_pArray);
        }
        m_pArray->release();
        // record the array state
        m_tStateStack.push(m_tState);
        m_tArrayStack.push(m_pArray);
    }
    else
    {
        m_tState = CE_SAX_NONE;
    }
}

void CEDictMaker::endElement(void *ctx, const char *name)
{
    CC_UNUSED_PARAM(ctx);
    ceSAXState curState = m_tStateStack.empty() ? CE_SAX_DICT : m_tStateStack.top();
    std::string sName((char*)name);
    if( sName == "dict" )
    {
        m_tStateStack.pop();
        m_tDictStack.pop();
        if ( !m_tDictStack.empty())
        {
            m_pCurDict = m_tDictStack.top();
        }
    }
    else if (sName == "array")
    {
        m_tStateStack.pop();
        m_tArrayStack.pop();
        if (! m_tArrayStack.empty())
        {
            m_pArray = m_tArrayStack.top();
        }
    }
    else if (sName == "true")
    {
        CCString *str = new CCString("1");
        if (CE_SAX_ARRAY == curState)
        {
            m_pArray->addObject(str);
        }
        else if (CE_SAX_DICT == curState)
        {
            if (m_pCurDict->objectForKey(m_sCurKey) != NULL)
            {
                CCLOG("CEDictMaker: Key '%s' duplication!!!", m_sCurKey.c_str());
            }
            CCAssert(m_pCurDict->objectForKey(m_sCurKey) == NULL, "CEDictMaker: Key duplication!!!");
            m_pCurDict->setObject(str, m_sCurKey);
        }
        str->release();
    }
    else if (sName == "false")
    {
        CCString *str = new CCString("0");
        if (CE_SAX_ARRAY == curState)
        {
            m_pArray->addObject(str);
        }
        else if (CE_SAX_DICT == curState)
        {
            m_pCurDict->setObject(str, m_sCurKey);
        }
        str->release();
    }
    m_tState = CE_SAX_NONE;
}

void CEDictMaker::textHandler(void *ctx, const char *ch, int len)
{
    CC_UNUSED_PARAM(ctx);
    if (m_tState == CE_SAX_NONE)
    {
        return;
    }

    ceSAXState curState = m_tStateStack.empty() ? CE_SAX_DICT : m_tStateStack.top();

    switch(m_tState)
    {
    case CE_SAX_KEY:
        m_sCurKey = std::string((char*)ch,0,len);
        break;
    case CE_SAX_INT:
    case CE_SAX_REAL:
    case CE_SAX_STRING:
        {
            CCAssert(!m_sCurKey.empty(), "not found key : <integet/real>");

            CEWString *pText = new CEWString(utf8_string_to_utf16_wstring(std::string((char*)ch,0,len)));

            if (CE_SAX_ARRAY == curState)
            {
                m_pArray->addObject(pText);
            }
            else if (CE_SAX_DICT == curState)
            {
                if (!m_pCurDict->setObject(pText, m_sCurKey) && 
					m_tState == CE_SAX_STRING && 
					dynamic_cast<CEWString*>(m_pCurDict->objectForKey(m_sCurKey)) != NULL)
				{
					wstring strUpdated = (dynamic_cast<CEWString*>(m_pCurDict->objectForKey(m_sCurKey)))->toStdString();
					strUpdated += pText->toStdString();
					CEWString *pTextUpdated = new CEWString(strUpdated);
					m_pCurDict->removeObjectForKey(m_sCurKey);
					m_pCurDict->setObject(pTextUpdated, m_sCurKey);
					pTextUpdated->release();
				}
            }
            pText->release();
            break;
        }
    default:
        break;
    }
}

}
